package com.codrim.cs.data.server.rpc.report;

import com.codrim.cs.data.rpc.dto.param.StatisticDataDTO;
import com.codrim.cs.data.rpc.enums.TimeDimension;
import com.codrim.cs.data.server.dao.entity.AbstractStatCsEntity;
import com.codrim.cs.data.server.subservice.TimeDimensionWithSdate;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author Liang.Zhuge on 14/08/2017.
 */
public abstract class AbstractStatDataHelper<T extends AbstractStatCsEntity> {
    private Logger logger = LoggerFactory.getLogger(this.getClass());
    private Map<TimeDimension, Map<String, T>> map = new HashMap<>();

    /**
     * 构造Map.key所需的枚举
     *
     * @return GroupKey[]
     */
    abstract GroupKey[] groupKeys();

    /**
     * 初始化关键标识字段
     *
     * @param sdate 特定维度的时间参数
     * @param dto   统计数据
     */
    protected abstract T initKeyFields(int sdate, StatisticDataDTO dto);

    private String groupKey(StatisticDataDTO dto) {
        StringBuilder sb = new StringBuilder();
        Arrays.stream(groupKeys()).forEach(
                item -> sb.append(Optional.ofNullable(item.getFieldValueConsumer.apply(dto)).map(Object::toString).orElse("")).append("_")
        );
        String result = sb.toString();
        logger.info("groupKey:{}", sb.toString());
        return result;
    }

    public void addStatisticData(TimeDimensionWithSdate timeDimensionWithSdate, StatisticDataDTO dto) {
        int sdate = timeDimensionWithSdate.getSdate();
        TimeDimension timeDimension = timeDimensionWithSdate.getTimeDimension();
        map.computeIfAbsent(timeDimension, k -> new HashMap<>(10))
                .computeIfAbsent(groupKey(dto), k -> initKeyFields(sdate, dto))
                .plus(dto);
    }

    public String mapDataSize() {
        return map.entrySet().stream().map(item -> item.getKey().key + ":" + item.getValue().size())
                .collect(Collectors.toList()).toString();
    }

    public Set<Map.Entry<TimeDimension, Map<String, T>>> elements() {
        return map.entrySet();
    }

    enum GroupKey {
        Symbol(StatisticDataDTO::getCurrencySymbol),
        AdvertiserId(StatisticDataDTO::getAdvId),
        AffiliateId(StatisticDataDTO::getAffId),
        OfferId(StatisticDataDTO::getOfferId),
        AdvAdvertiserManangerId(StatisticDataDTO::getAdvAdvertiserManagerId),
        AdvAffiliateManagerId(StatisticDataDTO::getAdvAffiliateManagerId),
        AffAdvertiserManagerId(StatisticDataDTO::getAffAdvertiserManagerId);

        Function<StatisticDataDTO, Object> getFieldValueConsumer;

        GroupKey(Function<StatisticDataDTO, Object> getFieldValueConsumer) {
            this.getFieldValueConsumer = getFieldValueConsumer;
        }
    }
}
